package com.yzg.sign.project.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2018/4/27.
 */
@Slf4j
public class HttpClientUtil
{
    private final static PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager();  //连接池管理器

    //类加载的时候 设置最大连接数 和 每个路由的最大连接数
    static {
        poolConnManager.setMaxTotal(2000);
        poolConnManager.setDefaultMaxPerRoute(1000);
    }

    private static CloseableHttpClient getCloseableHttpClient() {
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(poolConnManager)
//                .setRetryHandler(httpRequestRetryHandler)
                .build();

        return httpClient;
    }

    public static String doGet(String url, Map<String, String> param)
    {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = getCloseableHttpClient();

        String resultString = "";
        CloseableHttpResponse response = null;
        try
        {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null)
            {
                for (String key : param.keySet())
                {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200)
            {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (response != null)
                {
                    response.close();
                }
//                httpclient.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url)
    {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param)
    {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = getCloseableHttpClient();
        CloseableHttpResponse response = null;
        String resultString = "";
        try
        {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null)
            {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet())
                {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            resultString = e.getMessage();
        }
        finally
        {
            try
            {
                response.close();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String postParam(Map<String, Object> params, String url) throws Exception
    {
        HttpClient client = new HttpClient();
        PostMethod method = new PostMethod(url);
        //将原来写入postman中的form-data数据放入Map中
        for (Map.Entry<String, Object> entry : params.entrySet())
        {
            method.addParameter(entry.getKey(), String.valueOf(entry.getValue()));
        }
        try
        {
            client.executeMethod(method);
            byte[] response1 = method.getResponseBody();
            //获取请求后的响应体
            String result1 = new String(response1, "UTF-8");
            JSONObject js = JSONObject.parseObject(result1);
            log.info("收到的返回信息为：{} , Json后的内容：{}", result1, js);
            return result1;
        }
        catch (IOException ex)
        {
            log.info("推送请求出错{}" + ex.getMessage());
        }
        finally
        {
            //释放连接
            method.releaseConnection();
        }
        return null;
    }


    public static String doPost(String url)
    {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json)
    {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = getCloseableHttpClient();
        CloseableHttpResponse response = null;
        String resultString = "";
        try
        {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            resultString = e.getMessage();
        }
        finally
        {
            try
            {
                if(response!=null){
                    response.close();
                }
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();

            }
        }
        return resultString;
    }

    // 发起http请求时带有超时时间
    public static String doPostJsonWithTimeout(String url, String json,int timeout)
    {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = getCloseableHttpClient();
        RequestConfig config = RequestConfig.custom()
                .setSocketTimeout(timeout)
                .setConnectTimeout(timeout).build();
        CloseableHttpResponse response = null;
        String resultString = "";
        try
        {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            httpPost.setConfig(config);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            resultString = e.getMessage();
        }
        finally
        {
            try
            {
                if(response!=null){
                    response.close();
                }
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();

            }
        }
        return resultString;
    }

    static final CloseableHttpAsyncClient client =  getAsyncClient();

    //获取异步请求客户端
    public static CloseableHttpAsyncClient getAsyncClient() {
        if (client != null) {
            return client;
        }
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(5000)
                .setConnectionRequestTimeout(20000)//设置为10ms
                .build();

        //配置io线程
        IOReactorConfig ioReactorConfig = IOReactorConfig.custom().
                setIoThreadCount(Runtime.getRuntime().availableProcessors())
                .setSoKeepAlive(true)
                .build();
        //设置连接池大小
        ConnectingIOReactor ioReactor = null;
        try {
            ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
        } catch (IOReactorException e) {
            e.printStackTrace();
        }
        PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
        connManager.setMaxTotal(50);//最大连接数设置
        connManager.setDefaultMaxPerRoute(50);//per route最大连接数设置

        ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                HeaderElementIterator it = new BasicHeaderElementIterator
                        (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                while (it.hasNext()) {
                    HeaderElement he = it.nextElement();
                    String param = he.getName();
                    String value = he.getValue();
                    if (value != null && param.equalsIgnoreCase
                            ("timeout")) {
                        return Long.parseLong(value) * 1000;
                    }
                }
                return 60 * 1000;//如果没有约定，则默认定义时长为60s
            }
        };

        CloseableHttpAsyncClient client = HttpAsyncClients.custom()
                .setConnectionManager(connManager)
//                .setConnectionManagerShared(true)
                .setDefaultRequestConfig(requestConfig)
                .setKeepAliveStrategy(myStrategy)
                .build();
        client.start();
        return client;
    }



    public static void  doGetAsync(String url, Map<String, String> param, FutureCallback<HttpResponse> callback)
    {
        try
        {
            CloseableHttpAsyncClient  client = getAsyncClient();
//            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null)
            {
                for (String key : param.keySet())
                {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            HttpGet httpGet = new HttpGet(uri);

            // 执行请求
            client.execute(httpGet,  callback);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    // 增加传header的功能
    public static String doPostJson(String url, String json, Map<String, String> headers)
    {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = getCloseableHttpClient();
        CloseableHttpResponse response = null;
        String resultString = "";
        try
        {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            if (headers != null && headers.size() > 0)
            {
                headers.forEach((k, v) ->
                {
                    httpPost.setHeader(k, v);
                });
            }
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new com.yzg.sign.project.exception.NormalException(e.getMessage());
        }
        finally
        {
            try
            {
                if (response != null)
                {
                    response.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();

            }
        }
        return resultString;
    }

    public static String doGet(String url, Map<String, String> param,Map<String,String> headers) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = getCloseableHttpClient();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            if(headers != null && headers.size()>0){
                headers.forEach((k,v)->{
                    httpGet.setHeader(k,v);
                });
            }

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new com.yzg.sign.project.exception.NormalException(e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
//                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doPost(String url, Map<String, Object> param,Map<String,String> headers) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = getCloseableHttpClient();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, (String) param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpPost httpPost = new HttpPost(uri);

            if(headers != null && headers.size()>0){
                headers.forEach((k,v)->{
                    httpPost.setHeader(k,v);
                });
            }

            // 执行请求
            response = httpclient.execute(httpPost);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new com.yzg.sign.project.exception.NormalException(e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
//                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }




    public static   String getResult(HttpRequestBase httpRequest) throws IOException
    {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpResponse response = httpClient.execute(httpRequest);
        response.setHeader("Content-Type", "application/json;charset=utf8");
        InputStream inputStream = response.getEntity().getContent();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        String result = null;
        while ((line = bufferedReader.readLine()) != null) {
            result = String.valueOf(JSON.parse(line));
            System.out.println(result);
        }
        return  result;
    }




}